
package com.gitee.apanlh.util.id;

import com.gitee.apanlh.util.base.SingletonUtils;
import com.gitee.apanlh.util.date.format.DateTimeFormat;
import com.gitee.apanlh.util.encode.BinaryUtils;
import com.gitee.apanlh.util.encode.HexUtils;
import com.gitee.apanlh.util.net.addr.IpUtils;
import com.gitee.apanlh.util.random.RandomCodeUtils;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;


/**	
 * 	创建ID工具类
 * 	
 * 	@author Pan
 */
public class IdUtils {
	
	/** 机器码信息 */
	public static final int MACHINE = IpUtils.getMachine();
	/** 生成随机数	32位 <br>线程安全的下一个随机数,每次生成自增+1 */
    public static final AtomicInteger NEXT_INC = new AtomicInteger((ThreadLocalRandom.current()).nextInt());
    /** 初始化数字 大小写英文混合 4位 */
    public static final String DEFAULT_INIT_STR = RandomCodeUtils.generateMixedRandom(4);
    
    /**
	 * 	构造函数
	 * 
	 * 	@author Pan
	 */
	private IdUtils() {
		//	不允许外部实例
		super();
	}
	
	/**	
	 * 	生成标准UUID
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public static String getUuid() {
		return UUID.randomUUID().toString();
	}
	
	/**	
	 * 	生成不带-的UUID
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public static String getSimpleUuidSecond() {
		char[] srcChars = UUID.randomUUID().toString().toCharArray();
		int srcCharsLen = srcChars.length;
		
		char[] copyChars = new char[srcCharsLen - 4];
		//	标记位
		int srcStartIndex = 0;
		// copy数组的开始下标
		int copyStartIndex = 0;
		// copy长度
		int copyLen = 0;
		
		for (int i = 0; i < srcCharsLen; i++) {
			char c = srcChars[i];
			if (c == '-') {
				System.arraycopy(srcChars, srcStartIndex, copyChars, copyStartIndex, copyLen);
				srcStartIndex = i + 1;
				//	copy数组开始下标位置
				copyStartIndex = copyStartIndex + copyLen;
				//	清零记录的copy长度
				copyLen = 0;
			} else {
				copyLen++;
			}
			//	在记录最后一次时把最后一段UUID记录copy数组中
			if (i == (srcCharsLen -1)) {
				System.arraycopy(srcChars, srcStartIndex, copyChars, copyStartIndex, copyLen);
			}
		}
		return new String(copyChars);
	}
	
	/**	
	 * 	生成不带-的UUID
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public static String getSimpleUuid() {
		UUID uuid = UUID.randomUUID();
		long mostSigBits = uuid.getMostSignificantBits();
		long leastSigBits = uuid.getLeastSignificantBits();
		
		return uuidDigits(mostSigBits >> 32, 8)
				.concat(uuidDigits(mostSigBits >> 16, 4))
				.concat(uuidDigits(mostSigBits, 4))
				.concat(uuidDigits(leastSigBits >> 48, 4))
				.concat(uuidDigits(leastSigBits, 12));
	}
	
    /**	
     * 	获取已转换成二进制ID字符串-ID标识符号
     * 	
     * 	@author Pan
     * 	@param  id	已转换成二进制ID字符
     * 	@return	String	字符标识
     */
    public static String getIdUniqueStr(String id) {
    	return HexUtils.decodeToStr(id.substring(12, id.length() - 8));
    }
    
    /**	
     * 	获取十进制ID字符串-ID标识符号
     * 	
     * 	@author Pan
     * 	@param  id	已生成的id
     * 	@return	String
     */
    public static String getIdUniqueNumberStr(String id) {
    	return getIdUniqueStr(new BigInteger(id, 10).toString(16));
    }
    
    /**	
     * 	获取已转换成二进制的ID字符串-ID生成时间
     * 	
     * 	@author Pan
     * 	@param  id	已转换成二进制ID字符
     * 	@return	String	时间
     */
    public static String getIdDataStr(String id) {
    	DateTimeFormatter dateTimeFormatter = DateTimeFormat.getFormat("yyyy-MM-dd HH:mm:ss.SSS");
    	
    	return dateTimeFormatter.format(
			LocalDateTime.ofInstant(
				Instant.ofEpochMilli(HexUtils.decodeToLong("17".concat(id.substring(0, 9)))), 
				ZoneId.of("Asia/Shanghai")
			)
    	);
    }
    
    /**	
     * 	获取已转换成十进制ID字符串-ID生成时间
     * 	
     * 	@author Pan
     * 	@param  id	已转换成十进制ID字符
     * 	@return	String	时间
     */
    public static String getIdDataNumberStr(String id) {
    	return getIdDataStr(new BigInteger(id, 10).toString(16));
    }
    
    /**	
     * 	获取十进制唯一ID
     * 	<br>34位长度
     * 	
     * 	@author Pan
     * 	@return	String
     */
    public static String generateIdNumberStr() {
    	return new BigInteger(generateIdStr(), 16).toString(10);
    }
    
    /**	
     * 	
     * 	获取十进制唯一ID-自定义识别符
     * 	<br>34位长度
     * 	
     * 	@author Pan
     * 	@param 	customId	自定义唯一标识位置
     * 	@return	String
     */	
    public static String generateIdNumberStr(String customId) {
		return new BigInteger(generateIdStr(customId), 16).toString(10);
    }
    
    /**	
     * 	获取二进制唯一ID
     * 	
     * 	@author Pan
     * 	@param 	customId	自定义唯一标识位置
     * 	@return	String
     */
    public static String generateIdNumberHexStr(String customId) {
    	return new BigInteger(generateIdStr(customId), 16).toString(2);
    }
    
    /**	
     * 	创建唯一ID
     * 	<br>长度为28的唯一ID
     * 	<br>0-9 时间戳
     * 	<br>10-12  主机识别码
     *  <br>13-16 随机识别码
     * 	<br>17-28  序列
     * 	
     * 	@author Pan
     * 	@return	String
     */
    public static String generateIdStr() {
    	return generateIdStr(DEFAULT_INIT_STR);
    }
    
    /**	
     * 	创建十六进制唯一ID
     * 	<br>长度为28的唯一ID
     * 	<br>13-16 随机识别码 修改为自定义名称
     * 	
     * 	@author Pan
     * 	@param 	customId	自定义唯一标识位置
     * 	@return	String
     */
    public static String generateIdStr(String customId) {
    	int maxLen = 28;
    	StringBuilder strBuilder = new StringBuilder(maxLen).append(Long.toHexString(System.currentTimeMillis()).substring(2));
    	
    	if (MACHINE != 0) {
    		strBuilder.append(Integer.toHexString(MACHINE).substring(1, 4));
    	} else {
    		//	不存在增加随机数
    		strBuilder.append(HexUtils.encode(RandomCodeUtils.generateMixedRandom(3)));
    	}
    	
    	//	初始化标识符
    	int serviceNameLen = customId.length();
    	if (serviceNameLen > 4) {
    		strBuilder.append(HexUtils.encode(customId.substring(0, 4)));
    	} else if (serviceNameLen < 4) {
    		strBuilder.append(customId);
    		for (int append = serviceNameLen; append < 4; append++) {
    			//	代表意思为none
    			strBuilder.append(HexUtils.encode("n"));
    		}
    	} else {
    		strBuilder.append(HexUtils.encode(customId));
    	}
    	
    	//	自增数
    	byte[] array = ByteBuffer.wrap(new byte[4]).putInt(NEXT_INC.getAndIncrement()).array();
    	for (int i = 0, len = array.length; i < len; i++) {
    		int j = array[i] & 0xff;
    		//	补0
    		if (j < 16) {
    			strBuilder.append('0');
    		}
    		strBuilder.append(Integer.toHexString(j));
    	}
    	return strBuilder.toString();
    }
    
    /**
     * 	获取雪花ID生成时间
     *	<br>默认返回标准时间格式
     *	
     *	@author Pan
     * 	@param 	snowId 雪花ID
     * 	@return	String
     */
    public static String getSnowFlakeIdDate(String snowId) {
    	return getSnowFlakeIdDate(ClassConvertUtils.toLong(snowId));
    }
    
    /**
     * 	获取雪花ID生成时间
     *	<br>自定义时间格式
     *	
     *	@author Pan
     * 	@param 	snowId 雪花ID
     * 	@param  format 自定义时间格式
     * 	@return	String
     */
    public static String getSnowFlakeIdDate(String snowId, String format) {
    	return getSnowFlakeIdDate(ClassConvertUtils.toLong(snowId), format);
    }
    
    /**
     * 	获取雪花ID生成时间
     *	<br>默认返回标准时间格式
     *	
     *	@author Pan
     * 	@param 	snowId 雪花ID
     * 	@return	String
     */
    public static String getSnowFlakeIdDate(long snowId) {
    	return getSnowFlakeIdDate(snowId, "yyyy-MM-dd HH:mm:ss");
    }
    
    /**
     * 	获取雪花ID生成时间
     *	<br>自定义时间格式
     *	
     *	@author Pan
     * 	@param 	snowId 雪花ID
     * 	@param  format 自定义时间格式
     * 	@return	String
     */
    public static String getSnowFlakeIdDate(long snowId, String format) {
        String snowBinary = BinaryUtils.toStr(snowId);
        long timestamp = Long.parseUnsignedLong(snowBinary.substring(0, snowBinary.length() - (5 + 5 + 12)), 2) + SnowFlakeShort.START_TIMESTAMP;
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()).format(DateTimeFormat.getFormat(format));
    }
    
    /**	
     * 	雪花Id(long类型)
     * 	
     * 	@author Pan
     * 	@return	long
     */
    public static long snowFlakeId() {
    	return snowFlakeId(5L, 31L);
    }
    
    /**	
     * 	雪花Id(long类型)
     * 	
     * 	@author Pan
     * 	@param  workerId	机器节点标识(0-31)
     * 	@param  timeId		数据中心标识(0-31)
     * 	@return	long
     */
    public static long snowFlakeId(long workerId, long timeId) {
    	return SingletonUtils.get(SnowFlakeShort.class, workerId, timeId).nextId();
    }
    
    /**	
     * 	雪花Id(String类型)
     * 	<br>默认机器节点5
     * 	<br>默认中心节点标识31
     * 	
     * 	@author Pan
     * 	@return	String
     */
    public static String snowFlakeIdStr() {
    	return snowFlakeIdStr(5L, 31L);
    }
    
    /**	
     * 	雪花Id(String类型)
     * 	
     * 	@author Pan
     * 	@param  workerId	机器节点标识(0-31)
     * 	@param  timeId		数据中心标识(0-31)
     * 	@return	String
     */
    public static String snowFlakeIdStr(long workerId, long timeId) {
    	return SingletonUtils.get(SnowFlakeShort.class, workerId, timeId).nextIdStr();
    }
    
    /**	
   	 * 	UUID进制转换
   	 * 	
   	 * 	@author Pan
   	 * 	@param  val		值
   	 * 	@param  digits	进制
   	 * 	@return	String
   	 */
   	private static String uuidDigits(long val, int digits) {
   		long hi = 1L << (digits * 4);
   		return Long.toHexString(hi | (val & (hi - 1))).substring(1);
   	}
}
